package api

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/sirupsen/logrus"
	"io/ioutil"
	"net/http"
	"net/url"
)

type (
	Client struct {
		Host       string
		Token      string
		httpClient *http.Client
	}
)

func NewClient(host, token string) *Client {
	client := new(Client)
	client.Host = host
	client.Token = "Bearer " + token
	client.httpClient = new(http.Client)
	return client
}

func (c *Client) SearchVillages(req *SearchVillagesReq) (*SearchVillagesResp, error) {
	params := make(url.Values)
	params.Add("name", req.Name)
	params.Add("type", req.Type)
	params.Add("sectType", "")
	params.Add("pageSize", "100")

	apiUrl, _ := url.Parse(c.Host + SearchVillagesAPI)
	apiUrl.RawQuery = params.Encode()

	request, err := http.NewRequest(http.MethodGet, apiUrl.String(), nil)
	if err != nil {
		logrus.Errorf("调用接口[地址: %s][参数: %+v]失败, %s", SearchVillagesAPI, req, err)
		return nil, errors.New("查询小区出现系统错误")
	}
	request.Header.Add("Authorization", c.Token)

	resp, err := c.httpClient.Do(request)
	if err != nil {
		logrus.Errorf("调用接口[地址: %s][参数: %+v]失败, %s", SearchVillagesAPI, req, err)
		return nil, errors.New("查询小区出现网络异常")
	}
	// nolint
	defer resp.Body.Close()

	respBytesBuf, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		logrus.Errorf("调用接口[地址: %s][参数: %+v]失败, %s", SearchVillagesAPI, req, fmt.Errorf("读取响应数据失败: %s", err))
		return nil, errors.New("查询小区出现系统错误")
	}

	result := new(SearchVillagesResp)
	if err := json.Unmarshal(respBytesBuf, result); err != nil {
		logrus.Errorf("调用接口[地址: %s][参数: %+v]失败, %s", SearchVillagesAPI, req, fmt.Errorf("反序列化响应数据失败: %s", err))
		return nil, errors.New("查询小区出现系统错误")
	}

	return result, nil
}

func (c *Client) SearchUnits(req *SearchUnitsReq) (*SearchUnitsResp, error) {
	params := make(url.Values)
	params.Add("sectToi", req.SectToi)
	params.Add("unitNo", req.UnitNo)
	params.Add("pageSize", "100")
	params.Add("pageNumber", "1")

	apiUrl, _ := url.Parse(c.Host + SearchUnitsAPI)
	apiUrl.RawQuery = params.Encode()

	request, err := http.NewRequest(http.MethodGet, apiUrl.String(), nil)
	if err != nil {
		logrus.Errorf("调用接口[地址: %s][参数: %+v]失败, %s", SearchUnitsAPI, req, err)
		return nil, errors.New("查询单元列表出现系统错误")
	}
	request.Header.Add("Authorization", c.Token)

	resp, err := c.httpClient.Do(request)
	if err != nil {
		logrus.Errorf("调用接口[地址: %s][参数: %+v]失败, %s", SearchUnitsAPI, req, err)
		return nil, errors.New("查询单元列表出现网络异常")
	}
	// nolint
	defer resp.Body.Close()

	respBytesBuf, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		logrus.Errorf("调用接口[地址: %s][参数: %+v]失败, %s", SearchUnitsAPI, req, fmt.Errorf("读取响应数据失败: %s", err))
		return nil, errors.New("查询单元列表出现系统错误")
	}

	result := new(SearchUnitsResp)
	if err := json.Unmarshal(respBytesBuf, result); err != nil {
		logrus.Errorf("调用接口[地址: %s][参数: %+v]失败, %s", SearchUnitsAPI, req, fmt.Errorf("反序列化响应数据失败: %s", err))
		return nil, errors.New("查询单元列表出现系统错误")
	}

	return result, nil
}

func (c *Client) GetDeviceTypes() (*GetDeviceTypeResp, error) {
	apiUrl, _ := url.Parse(c.Host + GetDeviceTypesAPI)

	request, err := http.NewRequest(http.MethodGet, apiUrl.String(), nil)
	if err != nil {
		logrus.Errorf("调用接口[地址: %s][参数: %+v]失败, %s", GetDeviceTypesAPI, "", err)
		return nil, errors.New("查询设备类型出现系统错误")
	}
	request.Header.Add("Authorization", c.Token)

	resp, err := c.httpClient.Do(request)
	if err != nil {
		logrus.Errorf("调用接口[地址: %s][参数: %+v]失败, %s", GetDeviceTypesAPI, "", err)
		return nil, errors.New("查询设备类型出现网络错误")
	}
	// nolint
	defer resp.Body.Close()

	respBytesBuf, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		logrus.Errorf("调用接口[地址: %s][参数: %+v]失败, %s", GetDeviceTypesAPI, "", fmt.Errorf("读取响应数据失败: %s", err))
		return nil, errors.New("查询设备类型出现系统错误")
	}

	result := new(GetDeviceTypeResp)
	if err := json.Unmarshal(respBytesBuf, result); err != nil {
		logrus.Errorf("调用接口[地址: %s][参数: %+v]失败, %s", GetDeviceTypesAPI, "", fmt.Errorf("反序列化响应数据失败: %s", err))
		return nil, errors.New("查询设备类型出现系统错误")
	}

	return result, nil
}

func (c *Client) AddDevice(req *AddDeviceReq) (*CommonResp, error) {
	apiUrl, _ := url.Parse(c.Host + AddDeviceAPI)

	requestBody := new(bytes.Buffer)

	if err := json.NewEncoder(requestBody).Encode(req); err != nil {
		logrus.WithFields(logrus.Fields{
			"API":    apiUrl.String(),
			"Params": req,
		}).Errorf("调用添加设备接口失败, %s", err)
		return nil, errors.New("添加设备出现系统错误")
	}

	request, err := http.NewRequest(http.MethodPost, apiUrl.String(), requestBody)
	if err != nil {
		logrus.WithFields(logrus.Fields{
			"API":    apiUrl.String(),
			"Params": req,
		}).Errorf("调用添加设备接口失败, %s", err)
		return nil, errors.New("添加设备出现系统错误")
	}

	resp, err := c.httpClient.Do(request)
	if err != nil {
		logrus.WithFields(logrus.Fields{
			"API":    apiUrl.String(),
			"Params": req,
		}).Errorf("调用添加设备接口失败, %s", err)
		return nil, errors.New("添加设备出现网络异常")
	}
	defer resp.Body.Close()

	respBytesBuf, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		logrus.WithFields(logrus.Fields{
			"API":    apiUrl.String(),
			"Params": req,
		}).Errorf("调用添加设备接口失败, %s", err)
		return nil, errors.New("添加设备出现系统错误")
	}

	result := new(CommonResp)
	if err := json.Unmarshal(respBytesBuf, result); err != nil {
		logrus.WithFields(logrus.Fields{
			"API":    apiUrl.String(),
			"Params": req,
		}).Errorf("调用添加设备接口失败, %s", err)
		return nil, errors.New("添加设备出现系统错误")
	}

	return result, nil
}
